iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 19
5
Modern Web

寫給朋友的 PHP 從 0 到 100 實戰教程系列 第 19

Day 19. PHP教程: 實作收信開通帳號機制

  • 分享至 

  • xImage
  •  

首先在註冊流程中,新增帳號後方加上寄出認證信吧

// 新增到資料庫
$data_array = array(
  'username' => $username,
  'password' => $hashedpassword,
  'email' => $email,
  'active' => $activasion
);
Database::get()->insert("members", $data_array);

//以下是新的代碼
$id = Database::get()->getLastId(); // 取得最後新增的 member ID

$subject = "Registration Confirmation";
$body = "<p>Thank you for registering at demo site.</p>
<p>To activate your account, please click on this link: <a href='".Config::BASE_URL."activate/$id/$activasion'>".Config::BASE_URL."activate/$id/$activasion</a></p>
<p>Regards Site Admin</p>"; // 這邊用網址上的 GET 參數讓他回來網站時夾帶驗證碼

$mail = new Mail(Config::MAIL_USER_NAME, Config::MAIL_USER_PASSWROD);
$mail->setFrom(Config::MAIL_FROM, Config::MAIL_FROM_NAME);
$mail->addAddress($email);
$mail->subject($subject);
$mail->body($body);
$mail->send(); // 透過 GMAIL 送出

因為

Config::BASE_URL."activate/$id/$activasion"

所以送出後信件內的網址會是 http://127.0.0.1/game/activate/數字/亂碼

我們要在 activate 這個網址準備接收這兩組來驗證後開通帳號
所以在 route.php 要開新的 case

switch($route->getParameter(1)){
    case "activate";
        $data_array = array();
        $data_array['memberID'] = $route->getParameter(2);    
        $data_array['active'] = $route->getParameter(3);    

        $gump = new GUMP();
        $data_array = $gump->sanitize($data_array); 
        $validation_rules_array = array(
          'memberID'    => 'required|integer',
          'active'    => 'required|exact_len,32'
        );
        $gump->validation_rules($validation_rules_array);

        $filter_rules_array = array(
          'memberID' => 'trim|sanitize_string',
          'active' => 'trim',
        );
        $gump->filter_rules($filter_rules_array);
        $validated_data = $gump->run($data_array);

        if($validated_data === false) {
          //$error = $gump->get_readable_errors(false);
          exit;
        } else {
          foreach($validation_rules_array as $key => $val) {
            ${$key} = $data_array[$key];
          }
          $userVeridator = new UserVeridator();
          if($userVeridator->isReady2Active($id, $active)){
            $data_array['active'] = "Yes";
            Database::get()->update("members", $data_array, "memberID", $data_array['memberID']); 
            header('Location: login?action=active');
            exit;
          }else{
            echo "Your account could not be activated."; 
            exit;
          }
        }
    break;
}

邏輯上需要先驗證這組帳號是否存在,並且驗證碼相符,才能開通他。所以加上 isReady2Active 這個 function來使用

UserVeridator.php

/**
 * 驗證此帳號 ID 跟 開通碼 hash 是否已存在於資料庫中
 */
public function isReady2Active($id, $active){
    $result = Database::get()->execute('SELECT username FROM members WHERE memberID = :memberID AND active = :active', array(':memberID' => $id, ':active' => $active));
    if(isset($result[0]['username']) and !empty($result[0]['username'])){
      return true;
    }else{
      $this->error[] = 'Username provided is already in use.';
      return false;
    }
}

這樣一來就可以確認開通後 送到 login 畫面了

但是還要再補一個地方,之前我們做登入時沒有驗證 active 是否等於 Yes
所以再更新一次 UserVeridator 的 loginVerification function

UserVeridator.php

/**
 * 驗證帳號密碼是否正確可登入
 */
public function loginVerification($username, $password){
    $result = Database::get()->execute('SELECT * FROM members WHERE active = "Yes" AND username = :username', array(':username' => $username));
    if(isset($result[0]['memberID']) and !empty($result[0]['memberID'])) {
        $passwordObject = new Password();
        if($passwordObject->password_verify($password,$result[0]['password'])){
            return true;
        }
    }
    $this->error[] = 'Wrong username or password or your account has not been activated.';
    return false;
}

大功告成!


上一篇
Day 18. PHP教程: 實作登入與登出機制
下一篇
Day 20. PHP教學: 實作重置密碼流程
系列文
寫給朋友的 PHP 從 0 到 100 實戰教程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
a600masool
iT邦新手 5 級 ‧ 2020-03-25 16:24:20

感謝樓主分享,受益良多

提醒一下
如果 memberID 欄位設定為 AUTO_INCREMENT 自動累加
更新資料庫的時候如果把整個 $data_array 送進去會報錯,因為 ID 不可被更新

Database::get()->update("members", $data_array, "memberID", $data_array['memberID']); 
// 報錯

更改為

Database::get() -> update("user", array('active' => 'Yes'), "id", $data_array['memberID']);
// 可執行
0
e3561025
iT邦新手 5 級 ‧ 2021-11-04 23:27:37

感謝樓主分享
在route.php新增activate case中
前面使用${$key}這方式來獲得$memberID和$active
但後面使用isReady2Active($id,$active)這裡筆誤了
if($userVeridator->isReady2Active($id, $active)){ // 這裡沒有 $id的變數
需要改為
if($userVeridator->isReady2Active($memberID, $active)){

再根據上一位的講解做修改就能順利執行了

我要留言

立即登入留言